package com.shop.shopserver.service.impl;
import cn.hutool.core.bean.BeanUtil;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.shop.shopcommon.context.SecurityContext;
import com.shop.shopcommon.exception.Base.UserRegisterException;
import com.shop.shopcommon.properties.AliSmsProperties;
import com.shop.shoppojo.dto.SmsSendDTO;
import com.shop.shoppojo.dto.UserRegisterDTO;
import com.shop.shoppojo.entity.User;
import com.shop.shoppojo.vo.UserInfoVO;
import com.shop.shoppojo.vo.UserVO;
import com.shop.shopserver.mapper.UserMapper;
import com.shop.shopserver.service.UserService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.core.MessagePostProcessor;
import org.springframework.amqp.rabbit.connection.CorrelationData;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.ApplicationContext;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.util.concurrent.ListenableFutureCallback;

import java.math.BigDecimal;
import java.util.Random;
import java.util.UUID;
import java.util.concurrent.TimeUnit;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import static com.shop.shopcommon.constant.MessageConstant.USERNAME_NOT_NULL;
import static com.shop.shopcommon.constant.RabbitMQConstant.SMS_EXCHANGE;
import static com.shop.shopcommon.constant.RabbitMQConstant.SMS_SEND_REQUEST_ROUTING_KEY;
import static com.shop.shopcommon.constant.RedisConstant.USER_VERIFICATION_CODE_KEY;
@Slf4j
@Service
public class UserServiceImpl implements UserService {
    @Autowired
    private UserMapper userMapper;
    @Autowired
    private RedisTemplate<String,Object> redisTemplate;
    @Autowired
    private AliSmsProperties aliSmsProperties;
    @Autowired
    @Qualifier("rabbitSimpleTemplate")
    private RabbitTemplate rabbitSimpleTemplate;

//    private static final String phoneNumber_regex = "^(13[0-9]|14[01456879]|15[0-35-9]|16[2567]|17[0-8]|18[0-9]|19[0-35-9])\\d{8}$";
//      private static final String Password_regex = "^\\d{4,12}$";

    /**
     * 获取用户信息
     * @return
     */
    @Override
    public UserInfoVO getUserInfo() {
        //调用SecurityContext.getUsername获取username
        String username = SecurityContext.getUsername();
        //判断username是否为空
        if (username ==null || username.length() == 0){
            return new UserInfoVO();
        }
        //用LambdaQueryWrapper构造条件查询数据库中相同username的记录
        LambdaQueryWrapper<User> userLambdaQueryWrapper = new LambdaQueryWrapper<User>()
                .eq(User::getUsername,username);
        User user=userMapper.selectOne(userLambdaQueryWrapper);

        UserVO userVO = new UserVO();
        //将查询到的po类型记录复制为vo类型
        BeanUtil.copyProperties (user,userVO);
        //将复制好的vo类型返回在进一步封装的UserInfoVO类中用于展示
        return new UserInfoVO(userVO);
    }

    /**
     * 获取短信验证码
     * @param phone
     */
    @Override
    public String getNoteCode(String phone) throws Exception {
        // 判断用户名是否为空
        if (phone == null || phone.isEmpty()){
            throw new UsernameNotFoundException(USERNAME_NOT_NULL);
        }

        // 生成六位验证码
        Random random = new Random();
        Long randomNumber = (long) (random.nextInt(900000) + 100000);

        // 缓存验证码到redis中, 设置过期时间
        String key= USER_VERIFICATION_CODE_KEY+phone;
        redisTemplate.opsForValue().set(key,randomNumber,aliSmsProperties.getTimeout(), TimeUnit.SECONDS);

        // 封装发送短信的参数
        SmsSendDTO smsSendDTO = new SmsSendDTO(phone, randomNumber);
        String message = JSON.toJSONString(smsSendDTO);

        // 异步发送短信 不需要重试机制和生产者确认
        rabbitSimpleTemplate.convertAndSend(SMS_EXCHANGE, SMS_SEND_REQUEST_ROUTING_KEY, message);

        return String.valueOf(randomNumber);
    }

    /**
     * 用户注册
     * @param userRegisterDTO
     */
    public void register(UserRegisterDTO userRegisterDTO) {
        User user = new User();
        BeanUtils.copyProperties(userRegisterDTO,user);
        user.setValid(true);


        //获得传入的手机号和密码
        String phoneNumber =user.getUsername();
        //获得传入的密码
        String Password =user.getPassword();
        //获得传入的确认密码
        String ConfirmPassword =userRegisterDTO.getConfirmPassword();
        //获得传入的验证码
        String code =userRegisterDTO.getCode();

        // 手机号格式校验
        boolean isValidphoneNumber = isValidPhoneNumber(phoneNumber);
        if (phoneNumber == null || !isValidphoneNumber) {
            log.error("手机号码格式不正确");
        }else {
            log.info("手机号码格式正确");
        }


        // 密码格式校验格式验证成功才会进行确认密码校验
        boolean isValidpassword = isValidPassword(Password);
        if (Password == null || !isValidpassword) {
            log.error("密码格式错误：长度需在4至12位之间的纯数字密码");
        }else {
            if (!Password.equals(ConfirmPassword)) {
                log.error("两次密码不一致");
            }else {
                log.info("密码号码格式正确");
            }
        }


        //验证码确认
        Object codeFromRedis = redisTemplate.opsForValue().get(USER_VERIFICATION_CODE_KEY+user.getUsername());
        if (codeFromRedis == null ||!String.valueOf(codeFromRedis).equals(code.trim())){
            log.info("从Redis中取出的值为：{}",codeFromRedis);
            throw new UserRegisterException("验证码错误");
       }
        else  {
            log.info("从Redis中取出的值为：{}",codeFromRedis);
            log.info("验证码正确 ");
        }

        // 判断用户是否存在
        LambdaQueryWrapper<User> userLambdaQueryWrapper = new LambdaQueryWrapper<User>()
                .eq(User::getUsername,phoneNumber);
        if (userMapper.selectOne(userLambdaQueryWrapper) != null){
            throw new UserRegisterException("用户已存在");
        }

        //对密码进行BCrypt加密
        BCryptPasswordEncoder bCryptPasswordEncoder = new BCryptPasswordEncoder();
        String encodedPassword = bCryptPasswordEncoder.encode(Password);
        user.setPassword(encodedPassword);

        // 设置初始余额为0
        user.setPayMoney(new BigDecimal(0));
        userMapper.insert(user);
//        userMapper.insertUser(user);

    }



     // 判断手机号格式是否合法私有方法
    private static boolean isValidPhoneNumber(String phoneNumber) {
        // 常见号段精确匹配的正则表达式
        String regex = "^(13[0-9]|14[01456879]|15[0-35-9]|16[2567]|17[0-8]|18[0-9]|19[0-35-9])\\d{8}$";
        Pattern pattern = Pattern.compile(regex);
        Matcher matcher = pattern.matcher(phoneNumber);
        return matcher.matches();
    }

    //判断密码格式是否合法私有方法
    private static boolean isValidPassword(String Password) {
        // 常见号段精确匹配的正则表达式
        String regex =  "^\\d{4,12}$";
        Pattern pattern = Pattern.compile(regex);
        Matcher matcher = pattern.matcher(Password);
        return matcher.matches();
    }

}
